// A Vertex graph sorted by rank

#ifndef GRAPH_H 
#define GRAPH_H
#define GRAPHIDENTIFIER -1
#include <map>	
#include <set>
#include <utility>
#include "Vertex.h"
#include "VertexSet.h"
#include "RankSet.h"
#include "Group.h"
#include "VertexDirectory.h"
class TempvertexContainer;
#include "TempVertexContainer.h"
#include <cstdlib>

typedef map<long,RankSet*>::iterator GraphVerticesIterator;

using namespace std; 

class Graph
{
	public:
		Graph(int maxCouplesForMinimalRank = 5000, int randomIterations = 500, VertexDirectory* dir = NULL);
		~Graph();
		Vertex* GetMinimalRankedVertex(Group* group, bool makeInterchangeableChecks = false);
		void RemoveVertex(Vertex* vertex);
		void RemoveVertexBase(VertexBase* vertexBase);
		void RemoveVertexByName(Vertex *vertex);
		void RemoveVertexSet(VertexSet *vertexSet);
		void InsertVertex(Vertex* vertex, bool updateNeighbours = true);
		void InsertVertexSet(VertexSet* vertexSet, bool updateNeighbours = true);
		void InsertVertexBase(VertexBase* vertexBase, bool updateNeighbours = true);
		VertexSet* GetMinimalRankedVertexCouple(Group* group, bool makeInterchangeableChecks = false);
		void AddGroup(Group& group);
		void AddVertices(list<Vertex*> vertices);
		void AddRankSet(RankSet *rankSet);
		Graph* Clone(); // Deep copy
		Graph* CloneFromDirectory(VertexDirectory* dir); // Deep copy from specified directory
		int Count();
		bool IsVertexInGraph(Vertex *vertex);
		void SetTempContainer(TempVertexContainer *copy);
		VertexDirectory* GetVertexDirectory(); //may return null!
		void RemoveGroupVerticesFromGraph(Group* group);
		void FindVertexSetReplacements(VertexSet *vertexSet);

	private:	
		int m_MaxVertexCouplesForMininalRankSearch;
		int m_RandomIterations;
		map<long, RankSet*> m_Vertices ; // Vertices sorted by rank
		TempVertexContainer *m_TempContainer;
		VertexDirectory* m_Directory;
		// vertices have true is in rankset, false if in tempset and aren't in this if they
		// do not belong to graph
		map<VertexKey, bool> m_IsVertexInRankSet;

		void MoveVertexToTempSet(Vertex* vertex);
		void ReturnTempSetToGraph();
		void UpdateVertexRank(Vertex* vertex); // Update vertex's rank by updateModifier (can be +-), update the vertex map
		void RemoveEmptyRankSets();
		void ResetTempGroupIfNeeded(Group* group);
		int GetMaxRank();
		Vertex *GetRandomVertex(); 
		int CountWithoutTempSet();
		VertexSet* GetVertexCoupleAfterMaxIterations(VertexDirectory *dir);
		void UpdateAllNeighbours(Vertex *vertex);
		void AddVertexFromGroupOrList(Vertex *vertex);
		void CopyVertexDataFromDirectory(VertexDirectory *dir);
						
};

#endif
